home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 February: Tool Chest / Dev.CD Feb 00 TC.toast / pc / what's new? / sample code / graphics 3d / setupgl / setupdsp.c < prev    next >
Encoding:
Text File  |  1999-12-18  |  26.6 KB  |  834 lines

  1. /*
  2.     File:        SetupDSp.c
  3.  
  4.     Contains:    Functions to enable building and destorying a DSp fullscreen context
  5.  
  6.     Written by:    Geoff Stahl (ggs)
  7.  
  8.     Copyright:    Copyright © 1999 Apple Computer, Inc., All Rights Reserved
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <3>    12/18/99    ggs     Fixed err use before init
  13.          <2>    12/18/99    ggs     Fix headers
  14.          <1>    11/28/99    ggs     Initial add.  Split of just DSp handling functions.  Added total
  15.                                     device RAM checks, better step downs using actual supported
  16.                                     resolutions. Need to add user verify for contexts that require
  17.                                     it, integration of this in context step down, and a freq bit
  18.                                     field.
  19.          <1>    11/11/99    ggs     Initial Add
  20.  
  21.     Disclaimer:    IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
  22.                 ("Apple") in consideration of your agreement to the following terms, and your
  23.                 use, installation, modification or redistribution of this Apple software
  24.                 constitutes acceptance of these terms.  If you do not agree with these terms,
  25.                 please do not use, install, modify or redistribute this Apple software.
  26.  
  27.                 In consideration of your agreement to abide by the following terms, and subject
  28.                 to these terms, Apple grants you a personal, non-exclusive license, under Apple’s
  29.                 copyrights in this original Apple software (the "Apple Software"), to use,
  30.                 reproduce, modify and redistribute the Apple Software, with or without
  31.                 modifications, in source and/or binary forms; provided that if you redistribute
  32.                 the Apple Software in its entirety and without modifications, you must retain
  33.                 this notice and the following text and disclaimers in all such redistributions of
  34.                 the Apple Software.  Neither the name, trademarks, service marks or logos of
  35.                 Apple Computer, Inc. may be used to endorse or promote products derived from the
  36.                 Apple Software without specific prior written permission from Apple.  Except as
  37.                 expressly stated in this notice, no other rights or licenses, express or implied,
  38.                 are granted by Apple herein, including but not limited to any patent rights that
  39.                 may be infringed by your derivative works or by other works in which the Apple
  40.                 Software may be incorporated.
  41.  
  42.                 The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
  43.                 WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
  44.                 WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  45.                 PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
  46.                 COMBINATION WITH YOUR PRODUCTS.
  47.  
  48.                 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
  49.                 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  50.                 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  51.                 ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
  52.                 OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
  53.                 (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
  54.                 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  55. */
  56.  
  57.  
  58. // Usage notes: 
  59. // kUseFades enables gamma fades for activates and deactivates
  60. #define kUseFades
  61.  
  62. //kUseRAMCheck enables estimated video card RAM checks
  63. #define kUseRAMCheck
  64.  
  65.  
  66. // system includes ----------------------------------------------------------
  67.  
  68. //#include <MacTypes.h>
  69. //#include <Menus.h>
  70. #include <fp.h>
  71.  
  72. //#include <stdio.h>
  73. #include <string.h>
  74.  
  75.  
  76. // project includes ---------------------------------------------------------
  77.  
  78. #include "Error Handler.h"
  79. #include "SetupDSp.h"
  80.  
  81. // globals (internal/private) -----------------------------------------------
  82.  
  83. enum 
  84.     kMaxNumRes = 64, // max number of resolution slots
  85.     kMaxRefreshFreq = 75 
  86. }; 
  87.  
  88. Boolean gDSpStarted = false;
  89. Boolean gNeedFade = false;
  90.  
  91. // prototypes (internal/private) --------------------------------------------
  92.  
  93. DSpContextReference * ReserveUnusedDevices (GDHandle hGD);
  94. OSStatus FreeUnusedDevices (GDHandle hGD, DSpContextReference ** ppContextRefUnused);
  95. void BuildResolutionList (GDHandle hGD, Point * pResList, UInt32 * pFreqList);
  96. OSStatus DoDeviceRAMCheck (pstructGLInfo pcontextInfo, Point * pResList, UInt32 * pFreqList, GLint depthSizeSupport);
  97. Boolean DoContextStepDown (pstructGLInfo pcontextInfo, DSpContextAttributes * pContextAttributes, Point * pResList, UInt32 * pFreqList);
  98.  
  99.  
  100. // functions (internal/private) ---------------------------------------------
  101.  
  102. // ReserveUnusedDevices
  103.  
  104. // reserves contexts on unused devices to vprevent their selection by DSp, returns list of these devices
  105.  
  106. DSpContextReference * ReserveUnusedDevices (GDHandle hGD)
  107. {
  108.     DSpContextAttributes theContextAttributes;
  109.     DSpContextReference * pContextRefUnused = NULL;
  110.     GDHandle hDevice = DMGetFirstScreenDevice (true); // check number of screens
  111.     OSStatus err = noErr;
  112.     DisplayIDType displayID = 0;
  113.     short numDevices = 0, indexDevice = 0;
  114.     
  115.     do
  116.     {
  117.         numDevices++;
  118.         hDevice = DMGetNextScreenDevice (hDevice, true);
  119.     }
  120.     while (hDevice);
  121.     numDevices--; // only count unused screens
  122.     if (numDevices)
  123.     {
  124.         pContextRefUnused = (DSpContextReference *) NewPtr ((long) sizeof (DSpContextReference) * numDevices);
  125.         hDevice = DMGetFirstScreenDevice (true); // check number of screens
  126.         do
  127.         {
  128.             if (hDevice != hGD)    // if this device is not the one the user chose
  129.             {
  130.                 if (noErr == DSpReportError (DMGetDisplayIDByGDevice (hDevice, &displayID, false)))
  131.                     if (noErr == DSpReportError (DSpGetFirstContext (displayID, &pContextRefUnused [indexDevice]))) // get a context and
  132.                         if (noErr == DSpReportError (DSpContext_GetAttributes (pContextRefUnused [indexDevice], &theContextAttributes))) // find attributes
  133.                             DSpReportError (DSpContext_Reserve (pContextRefUnused [indexDevice], &theContextAttributes)); // reserve it
  134.                 indexDevice++;
  135.             }
  136.             hDevice = DMGetNextScreenDevice (hDevice, true);
  137.         }
  138.         while (hDevice);
  139.     }
  140.     return pContextRefUnused;
  141. }
  142.  
  143. // --------------------------------------------------------------------------
  144.  
  145. // FreeUnusedDevices
  146.  
  147. // frees screen that were previously reserved to prevent selection
  148.  
  149. OSStatus FreeUnusedDevices (GDHandle hGD, DSpContextReference ** ppContextRefUnused)
  150. {
  151.     OSStatus err = noErr;
  152.     GDHandle hDevice = DMGetFirstScreenDevice (true); // check number of screens
  153.     short indexDevice = 0;
  154.  
  155.     do
  156.     {
  157.         if (hDevice != hGD)    // if this device is not the one the user chose
  158.         {
  159.             err = DSpContext_Release (*ppContextRefUnused [indexDevice]); // release it
  160.             DSpReportError (err);
  161.             indexDevice++;
  162.         }
  163.         hDevice = DMGetNextScreenDevice (hDevice, true);
  164.     }
  165.     while (hDevice);
  166.     
  167.     DisposePtr ((Ptr) *ppContextRefUnused);
  168.     *ppContextRefUnused = NULL;
  169.     return err;
  170. }
  171.  
  172. // --------------------------------------------------------------------------
  173.  
  174. // BuildResolutionList
  175.  
  176. // builds a list of supported resolutions and frequencies for GDevice
  177.  
  178. void BuildResolutionList (GDHandle hGD, Point * pResList, UInt32 * pFreqList)
  179. {
  180.     DSpContextAttributes theContextAttributes;
  181.     DSpContextReference currContext;
  182.     OSStatus err;
  183.     DisplayIDType displayID = 0;
  184.     short i;
  185.     
  186.     for (i = 0; i < kMaxNumRes; i++)    // clear resolution list
  187.     {
  188.         pResList [i].h = 0x7FFF;
  189.         pResList [i].v = 0x7FFF;
  190.         pFreqList [i] = 0;            // some context require certain frequencies find highest for each (not higher than 85
  191.     }
  192.  
  193.     err = DMGetDisplayIDByGDevice (hGD, &displayID, true);
  194.     if (noErr != err)
  195.         ReportErrorNum ("DMGetDisplayIDByGDevice error", err);
  196.     else
  197.     {
  198.         if (noErr == DSpReportError (DSpGetFirstContext (displayID, &currContext)))
  199.             do
  200.             {    
  201.                 // insertion sort into resolution list
  202.                 if (noErr == DSpReportError (DSpContext_GetAttributes (currContext, &theContextAttributes)))
  203.                 {
  204.                     Point pntTemp;
  205.                     Boolean fDone = false;
  206.                     short i = 0;
  207.                     while ((i < kMaxNumRes) && (!fDone))
  208.                     {
  209.                         if ((theContextAttributes.displayWidth == pResList [i].h) && (theContextAttributes.displayHeight == pResList [i].v)) //skip
  210.                         {
  211.                             if ((pFreqList [i] == 0) || ((theContextAttributes.frequency <= (kMaxRefreshFreq << 16)) && (theContextAttributes.frequency > pFreqList [i])))
  212.                                 pFreqList [i] = theContextAttributes.frequency;
  213.                             break;
  214.                         }
  215.                         if (theContextAttributes.displayWidth * theContextAttributes.displayHeight < pResList [i].h * pResList [i].v) //insert
  216.                         {
  217.                             pntTemp = pResList [i];
  218.                             pResList [i].h = theContextAttributes.displayWidth;
  219.                             pResList [i].v = theContextAttributes.displayHeight;
  220.                             pFreqList [i] = theContextAttributes.frequency;
  221.                             fDone = true;
  222.                         }
  223.                         i++;
  224.                     }
  225.                     // i points to next element to switch; finish array swaps (if 
  226.                     while ((i < kMaxNumRes) && (fDone))
  227.                     {
  228.                         Point pntSwitch = pResList [i];
  229.                         pResList [i++] = pntTemp;
  230.                         pntTemp = pntSwitch;
  231.                     }
  232.                 }
  233.                 err = DSpGetNextContext (currContext, &currContext);
  234.                 if (noErr != err)
  235.                 {
  236.                     if (kDSpContextNotFoundErr != err) 
  237.                         DSpReportError (err);
  238.                     currContext = 0;    // ensure we drop out
  239.                 }
  240.             } 
  241.             while (currContext);
  242.         else
  243.             ReportErrorNum ("DSpGetFirstContext error", err);
  244.     }    
  245.     // zeroize unused elements
  246.     for (i = 0; i < kMaxNumRes; i++)
  247.         if ((pResList [i].h == 0x7FFF) || (pResList [i].v == 0x7FFF))
  248.         {
  249.             pResList [i].h = 0;
  250.             pResList [i].v = 0;
  251.         }
  252. }
  253.  
  254. // --------------------------------------------------------------------------
  255.  
  256. // DoDeviceRAMCheck
  257.  
  258. // checks requested allocation against device RAM
  259. // Note: may modify pcontextInfo
  260. // this should be equal or less strigent than OpenGL actual allocation to avoid failing on valid drawables
  261.  
  262. OSStatus DoDeviceRAMCheck (pstructGLInfo pcontextInfo, Point * pResList, UInt32 * pFreqList, GLint depthSizeSupport)
  263. {
  264.     float frontBufferFactor = 1.0, backBufferFactor = 0.0; // amount of screen(front) or request(back) sized buffers required, in bytes
  265.     Point pntFrontBuffer; // size of front buffer that wil be allocated
  266.     short i, indexFrontBuffer; 
  267.     OSStatus err = noErr;
  268.  
  269.     // must take into account the entire front buffer, so figure out what screen resolution we are really going to use
  270.     // find front buffer for request
  271.     i = 0;
  272.     while (((pResList [i].h < pcontextInfo->width) || (pResList [i].v < pcontextInfo->height)) &&
  273.            ((pResList [i].h != 0) || (pResList [i].v != 0)) &&
  274.            (i < kMaxNumRes))
  275.         i++;
  276.     // save front buffer sizes
  277.     pntFrontBuffer.h = pResList [i].h;
  278.     pntFrontBuffer.v = pResList [i].v;
  279.     // if we have a valid frequnecy for the context set it (to ensure a good selection
  280.     pcontextInfo->freq = pFreqList [i] >> 16;
  281.     indexFrontBuffer = i;
  282.     
  283.     // front buffers required
  284.     if (16 == pcontextInfo->pixelDepth)
  285.         frontBufferFactor *= 2.0;
  286.     else if (32 == pcontextInfo->pixelDepth)
  287.         frontBufferFactor *= 4.0;
  288.         
  289.     // back buffers required    
  290.     backBufferFactor = 0.0;
  291.     i = 0;
  292.     while (64 > i)
  293.         if (AGL_DOUBLEBUFFER == pcontextInfo->aglAttributes[i++])
  294.         {
  295.             if (16 == pcontextInfo->pixelDepth)
  296.                 backBufferFactor = 2.0;
  297.             else if (32 == pcontextInfo->pixelDepth)
  298.                 backBufferFactor = 4.0;
  299.             break;
  300.         }
  301.     i = 0;
  302.     while (64 > i)
  303.         if (AGL_DEPTH_SIZE == pcontextInfo->aglAttributes[i++])
  304.         {
  305.             short requestDepth = pcontextInfo->aglAttributes[i];
  306.             GLint bit = 0x00000001;
  307.             short currDepth = 0, prevDepth = 0;
  308.             if (depthSizeSupport)
  309.             {
  310.                 do
  311.                 {
  312.                     if (bit & depthSizeSupport)    // if the card supports the depth
  313.                     {
  314.                         prevDepth = currDepth;
  315.                         switch (bit)
  316.                         {
  317.                             case AGL_1_BIT:
  318.                                 currDepth = 1;
  319.                                 break;
  320.                             case AGL_2_BIT:
  321.                                 currDepth = 2;
  322.                                 break;
  323.                             case AGL_3_BIT:
  324.                                 currDepth = 3;
  325.                                 break;
  326.                             case AGL_4_BIT:
  327.                                 currDepth = 4;
  328.                                 break;
  329.                             case AGL_5_BIT:
  330.                                 currDepth = 5;
  331.                                 break;
  332.                             case AGL_6_BIT:
  333.                                 currDepth = 6;
  334.                                 break;
  335.                             case AGL_8_BIT:
  336.                                 currDepth = 8;
  337.                                 break;
  338.                             case AGL_10_BIT:
  339.                                 currDepth = 10;
  340.                                 break;
  341.                             case AGL_12_BIT:
  342.                                 currDepth = 12;
  343.                                 break;
  344.                             case AGL_16_BIT:
  345.                                 currDepth = 16;
  346.                                 break;
  347.                             case AGL_24_BIT:
  348.                                 currDepth = 24;
  349.                                 break;
  350.                             case AGL_32_BIT:
  351.                                 currDepth = 32;
  352.                                 break;
  353.                             case AGL_48_BIT:
  354.                                 currDepth = 48;
  355.                                 break;
  356.                             case AGL_64_BIT:
  357.                                 currDepth = 64;
  358.                                 break;
  359.                             case AGL_96_BIT:
  360.                                 currDepth = 96;
  361.                                 break;
  362.                             case AGL_128_BIT:
  363.                                 currDepth = 128;
  364.                                 break;
  365.                         }
  366.                     }
  367.                     bit *= 2;
  368.                 } while (!((requestDepth > prevDepth) && (requestDepth <= currDepth)) && (bit < AGL_128_BIT + 1));
  369.             }
  370.             else // no card depth support info
  371.                 currDepth = requestDepth;  // we don't have card info thus assume we can support exact depth requested (may fail later but will always be equal or less stringent)
  372.             if ((AGL_128_BIT >= bit) && (0 != currDepth))
  373.                 backBufferFactor += (float) currDepth / 8.0;
  374.             break;
  375.         }
  376.         
  377.     // What we now have:
  378.     //  pcontextInfo->width, height: request width and height
  379.     //  pResList: sorted list of resolutions supported on this display
  380.     //  pntFrontBuffer : size of front buffer that will currently be allocated
  381.     //  indexFrontBuffer: position in array of current front buffer request
  382.     //  frontBufferFactor: number of screen resolution size buffers that will be needed
  383.     //  backBufferFactor: number of request size buffers that will be needed
  384.     
  385.     // find a context size that can support our texture requirements in the current total VRAM
  386.     if ((pcontextInfo->VRAM - pcontextInfo->textureRAM) < (pntFrontBuffer.h * pntFrontBuffer.v * frontBufferFactor + 
  387.                                                            pcontextInfo->width * pcontextInfo->height * backBufferFactor))
  388.     {
  389.         if (pcontextInfo->fDepthMust && pcontextInfo->fSizeMust)
  390.         {
  391.             // cannot accomdate request
  392.             ReportError ("Not enough total VRAM for drawable and textures");
  393.             return err;
  394.         }
  395.         else if (pcontextInfo->fSizeMust) // if we can adjust the size, try adjusting the 
  396.         {
  397.             // try 16 bit if must size is true
  398.             if ((pcontextInfo->pixelDepth > 16) &&
  399.                 (pcontextInfo->VRAM - pcontextInfo->textureRAM) > (pntFrontBuffer.h * pntFrontBuffer.v * frontBufferFactor / 2.0 + 
  400.                                                                       pcontextInfo->width * pcontextInfo->height * (backBufferFactor - 2.0)))
  401.                 pcontextInfo->pixelDepth = 16;
  402.             else
  403.             {
  404.                 // cannot accomdate request
  405.                 ReportError ("Not enough total VRAM for drawable and textures");
  406.                 return err;
  407.             }
  408.         }
  409.         else // can adjust size and might be able to adjust dopth
  410.         {    // make drawable fit
  411.             Boolean fFound = false;
  412.             // see if we can just adjust the pixel depth
  413.             if ((pcontextInfo->pixelDepth > 16) &&    // if we are requesting 32 bit
  414.                 (!pcontextInfo->fDepthMust) &&         // if we can adjust the pixel depth
  415.                 (pcontextInfo->VRAM - pcontextInfo->textureRAM) > (pntFrontBuffer.h * pntFrontBuffer.v * frontBufferFactor / 2.0 + 
  416.                                                                       pcontextInfo->width * pcontextInfo->height * (backBufferFactor - 2.0)))
  417.             {
  418.                 fFound = true;
  419.                 pcontextInfo->pixelDepth = 16;
  420.             }
  421.             else // pixel depth alone wont do it
  422.             {
  423.                 short i = indexFrontBuffer - 1;
  424.                 while (i >= 0)
  425.                 {
  426.                     //
  427.                     if ((pcontextInfo->VRAM - pcontextInfo->textureRAM) > (pResList [i].h * pResList [i].v * frontBufferFactor + 
  428.                                                                               pResList [i].h * pResList [i].v * backBufferFactor))
  429.                     {
  430.                         fFound = true;
  431.                         pcontextInfo->width = pResList [i].h;
  432.                         pcontextInfo->height = pResList [i].v;
  433.                         pcontextInfo->freq = pFreqList [i] >> 16;
  434.                         break;
  435.                     }
  436.                     else if ((pcontextInfo->pixelDepth > 16) &&    // if we are requesting 32 bit
  437.                              (!pcontextInfo->fDepthMust) &&     // if we can adjust the pixel depth
  438.                              (pcontextInfo->VRAM - pcontextInfo->textureRAM) > (pResList [i].h * pResList [i].v * frontBufferFactor / 2.0 + 
  439.                                                                                 pResList [i].h * pResList [i].v * (backBufferFactor - 2.0)))
  440.                     {
  441.                         fFound = true;
  442.                         pcontextInfo->width = pResList [i].h;
  443.                         pcontextInfo->height = pResList [i].v;
  444.                         pcontextInfo->freq = pFreqList [i] >> 16;
  445.                         pcontextInfo->pixelDepth = 16;
  446.                         break;
  447.                     }
  448.                     i--;
  449.                 }
  450.                 // we tried the smallest screen size and still need to use less VRAM, adjust backbuffer to what is available
  451.                 if ((!fFound) && (((pcontextInfo->VRAM - pcontextInfo->textureRAM) - pResList [0].h * pResList [0].v * frontBufferFactor) > 0))
  452.                 {
  453.                     float factor;
  454.                     fFound = true;
  455.                     factor = sqrt((float) (pcontextInfo->width * pcontextInfo->height * backBufferFactor) / 
  456.                                   (float) ((pcontextInfo->VRAM - pcontextInfo->textureRAM) - pResList [0].h * pResList [0].v * frontBufferFactor));
  457.                     pcontextInfo->width /= factor;
  458.                     pcontextInfo->height /= factor;
  459.                     pcontextInfo->freq = pFreqList [0] >> 16;
  460.                 }
  461.             }
  462.             if (!fFound)
  463.             {
  464.                 // cannot accomdate request
  465.                 ReportError ("Not enough total VRAM for drawable and textures");
  466.                 return err;
  467.             }
  468.  
  469.         }
  470.     }
  471.     return noErr;
  472. }
  473.  
  474. // --------------------------------------------------------------------------
  475.  
  476. // DoContextStepDown
  477.  
  478. // steps down through frequencies, depths and sizes to try to find a valid context
  479. // bounded by flags for SizeMust and DepthMust
  480. // Note: may modify pcontextInfo
  481.  
  482. Boolean DoContextStepDown (pstructGLInfo pcontextInfo, DSpContextAttributes * pContextAttributes, Point * pResList, UInt32 * pFreqList)
  483. {
  484.     // find current resolution
  485.     short i = 0; 
  486.     while (((pResList [i].h <= pContextAttributes->displayWidth) || (pResList [i].v <= pContextAttributes->displayHeight)) && 
  487.             ((pResList [i].h != 0) || (pResList [i].v != 0)) &&
  488.             (i < kMaxNumRes))
  489.         i++;
  490.     i--; // i points to index of current resolution
  491.     
  492.     if (pcontextInfo->fSizeMust) // adjust depth only
  493.     {
  494.         if (pcontextInfo->pixelDepth > 16)    // also try pixel depth step down
  495.         {
  496.             pContextAttributes->displayBestDepth = 16;
  497.             pContextAttributes->backBufferBestDepth = 16;
  498.         }
  499.         else
  500.             return false; // no more options to try
  501.     }
  502.     else if (pcontextInfo->fDepthMust) // adjust size only
  503.     {
  504.         if (i > 0)
  505.         {
  506.             i--; // i was pointing at current resolution, now it is pointing at new resolution to try
  507.             // set new resolution
  508.             pContextAttributes->displayWidth = pResList [i].h;
  509.             pContextAttributes->displayHeight = pResList [i].v;
  510.             pcontextInfo->freq = pFreqList [i] >> 16;
  511.         }
  512.         else
  513.             return false;
  514.     }
  515.     else // adjust size and depth
  516.     {
  517.         if (pContextAttributes->displayBestDepth > 16)
  518.         {
  519.             pContextAttributes->displayBestDepth = 16;
  520.             pContextAttributes->backBufferBestDepth = 16;
  521.         }
  522.         else if (i > 0)
  523.         {
  524.             i--; // i was pointing at current resolution, now it is pointing at new resolution to try
  525.             // reset pixel depth
  526.             pContextAttributes->displayBestDepth = pcontextInfo->pixelDepth;
  527.             pContextAttributes->backBufferBestDepth = pcontextInfo->pixelDepth;
  528.             // set new resolution
  529.             pContextAttributes->displayWidth = pResList [i].h;
  530.             pContextAttributes->displayHeight = pResList [i].v;
  531.             pcontextInfo->freq = pFreqList [i] >> 16;
  532.         }
  533.         else
  534.             return false;
  535.             
  536.     }
  537.     return true;
  538. }
  539.  
  540. #pragma mark -
  541. // functions (public) -------------------------------------------------------
  542.  
  543. // StartDSp
  544.  
  545. // handles starting up DrawSprocket
  546.  
  547. OSStatus StartDSp (void)
  548. {
  549.     OSStatus err = noErr;
  550.     
  551.     if (!gDSpStarted)
  552.     {
  553.         // check for DSp
  554.         if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) DSpStartup) 
  555.         {
  556.             ReportError ("DSp not installed");
  557.             return noErr;
  558.         }    
  559.  
  560.         err = DSpReportError (DSpStartup()); // start DSp
  561.         if (noErr != err)
  562.             return err;
  563.         else
  564.             gDSpStarted = true;
  565.     }
  566.     return err;        
  567. }
  568.  
  569. // --------------------------------------------------------------------------
  570.  
  571. // ShutdownDSpContext
  572.  
  573. // shuts down DrawSprocket
  574.  
  575. void ShutdownDSp (void)
  576. {
  577.     if (gDSpStarted)
  578.     {
  579.         DSpShutdown ();
  580.         gDSpStarted = false;
  581.     }
  582. }
  583.  
  584. #pragma mark -
  585. // --------------------------------------------------------------------------
  586.  
  587. // BuildDSpContext
  588.  
  589. // contexInfo and tries to allocate the corresponding DSp context
  590.  
  591. // Inputs:     hGD: GDHandle to device to look at
  592. //            pcontextInfo: request and requirements for cotext and drawable
  593.  
  594. // Outputs: *pdspContext as allocated
  595. //            pcontextInfo:  allocated parameters
  596.  
  597. // if fail to allocate: pdspContext will be NULL
  598. // if error: will return error pdspContext will be NULL
  599.  
  600. OSStatus BuildDSpContext (DSpContextReference* pdspContext, GDHandle hGD, GLint depthSizeSupport, pstructGLInfo pcontextInfo)
  601. {
  602.     DSpContextAttributes theContextAttributes, foundAttributes;
  603.     DSpContextReference * pContextRefUnused;
  604.     UInt32 aFreqList [kMaxNumRes];
  605.     Point aResList [kMaxNumRes]; // list for resolution information
  606.     OSStatus err = noErr;
  607.     
  608.     *pdspContext = 0;
  609.  
  610.     if (!gDSpStarted)
  611.     {
  612.         // check for DSp
  613.         if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) DSpStartup) 
  614.         {
  615.             ReportError ("DSp not installed");
  616.             return noErr;
  617.         }    
  618.  
  619.         err = DSpReportError (DSpStartup()); // start DSp
  620.         if (noErr != err)
  621.         {
  622.             return err;
  623.         }
  624.         else
  625.             gDSpStarted = true;
  626.     }        
  627.  
  628.     // reserve contexts on other screens to prevent their selection
  629.     pContextRefUnused = ReserveUnusedDevices (hGD);
  630.     
  631.     // build resolution list
  632.     BuildResolutionList (hGD, aResList, aFreqList);
  633.     
  634.     // handle default pixel depths
  635.     if (pcontextInfo->pixelDepth == 0)    // default
  636.     {
  637.         pcontextInfo->pixelDepth = (**(**hGD).gdPMap).pixelSize;
  638.         if (pcontextInfo->pixelDepth < 16)
  639.             pcontextInfo->pixelDepth = 16;
  640.     }
  641.  
  642. #ifdef kUseRAMCheck
  643.     if (noErr != DoDeviceRAMCheck (pcontextInfo, aResList, aFreqList, depthSizeSupport))
  644.         return err;
  645. #endif // kUseRAMCheck
  646.  
  647.     // Note: DSp < 1.7.3 REQUIRES the back buffer attributes even if only one buffer is required
  648.     memset(&theContextAttributes, 0, sizeof (DSpContextAttributes));
  649.     theContextAttributes.displayWidth                = pcontextInfo->width;
  650.     theContextAttributes.displayHeight                = pcontextInfo->height;
  651.     theContextAttributes.displayBestDepth            = pcontextInfo->pixelDepth;
  652.     theContextAttributes.backBufferBestDepth        = pcontextInfo->pixelDepth;
  653.     do
  654.     {    
  655.         theContextAttributes.frequency                = pcontextInfo->freq * 0x10000;
  656.         theContextAttributes.colorNeeds                = kDSpColorNeeds_Require;
  657.         theContextAttributes.displayDepthMask        = kDSpDepthMask_All;
  658.         theContextAttributes.backBufferDepthMask    = kDSpDepthMask_All;
  659.         theContextAttributes.pageCount                = 1; // only the front buffer is needed
  660.         err = DSpFindBestContext(&theContextAttributes, pdspContext);
  661.         if (noErr != err)    // if we had any errors, reset for next try
  662.             if (!DoContextStepDown (pcontextInfo, &theContextAttributes, aResList, aFreqList))
  663.                 break; // have run out of options
  664.     } while (err == kDSpContextNotFoundErr);
  665.  
  666.     // check find best context errors
  667.     if (kDSpContextNotFoundErr == err)
  668.     {    
  669.         *pdspContext = 0;
  670.         return noErr;
  671.     }
  672.     else if (noErr != err)
  673.     {
  674.         DSpReportError (err);
  675.         *pdspContext = 0;
  676.         return err;
  677.     }
  678.     
  679.     err = DSpReportError (DSpContext_GetAttributes (*pdspContext, &foundAttributes));
  680.     if (noErr != err)
  681.     {
  682.         *pdspContext = 0;
  683.         return err;
  684.     }
  685.     // reset width and height to full screen and handle our own centering
  686.     // HWA will not correctly center less than full screen size contexts
  687.     theContextAttributes.displayWidth         = foundAttributes.displayWidth;
  688.     theContextAttributes.displayHeight         = foundAttributes.displayHeight;
  689.     theContextAttributes.pageCount            = 1; // only the front buffer is needed
  690.     theContextAttributes.contextOptions        = 0 | kDSpContextOption_DontSyncVBL; // no page flipping and no VBL sync needed
  691.  
  692.     err = DSpReportError (DSpContext_Reserve(*pdspContext, &theContextAttributes )); // reserve our context
  693.     if (noErr != err)
  694.     {
  695.         *pdspContext = 0;
  696.         return err;
  697.     }
  698.     if (gNeedFade == true)
  699.     {
  700.         DSpReportError (DSpContext_CustomFadeGammaOut (NULL, NULL, 5));
  701.         gNeedFade = false;
  702.     }
  703.     err = DSpReportError (DSpContext_SetState (*pdspContext, kDSpContextState_Active)); // activate our context
  704.     if (noErr != err)
  705.     {
  706.         DSpContext_Release (*pdspContext);
  707.         *pdspContext = 0;
  708.         return err;
  709.     }
  710.  
  711.     FreeUnusedDevices (hGD, &pContextRefUnused);
  712.     
  713.     if (!pcontextInfo->fSizeMust)    // if we got whatever was available
  714.     {
  715.         // reset inputs to what was allocated (constrain aspect ratio)
  716.         // unless we ask for smaller, then leave the same
  717.         if ((pcontextInfo->width > foundAttributes.displayWidth) || (pcontextInfo->height > foundAttributes.displayHeight))
  718.         {
  719.             float hFactor = (float) pcontextInfo->width / (float) foundAttributes.displayWidth;
  720.             float vFactor = (float) pcontextInfo->height / (float) foundAttributes.displayHeight;
  721.             if (hFactor > vFactor)
  722.             {
  723.                 pcontextInfo->width = foundAttributes.displayWidth;
  724.                 pcontextInfo->height /= hFactor;    
  725.             }
  726.             else
  727.             {
  728.                 pcontextInfo->height = foundAttributes.displayHeight;
  729.                 pcontextInfo->width /= vFactor;    
  730.             }
  731.         }
  732.     }
  733.     // else still use inputs to allocate drawable
  734.     
  735.     pcontextInfo->freq = foundAttributes.frequency / 0x10000;
  736.     pcontextInfo->pixelDepth = foundAttributes.displayBestDepth;
  737.  
  738.     return noErr;
  739. }
  740.  
  741. //-----------------------------------------------------------------------------------------------------------------------
  742.  
  743. // Deactivates and dumps context
  744.  
  745. void DestroyDSpContext (DSpContextReference* pdspContext)
  746. {
  747.     if (gDSpStarted)
  748.     {
  749.         if (*pdspContext)
  750.         {
  751.             DSpContext_SetState(*pdspContext, kDSpContextState_Inactive );
  752.             DSpReportError (DSpContext_CustomFadeGammaIn (NULL, NULL, 5));
  753.             DSpContext_Release (*pdspContext);
  754.             *pdspContext = NULL;
  755.         }
  756.     }
  757. }
  758.  
  759.  
  760. #pragma mark -
  761. //-----------------------------------------------------------------------------------------------------------------------
  762.  
  763. OSStatus DSpContext_CustomFadeGammaIn (DSpContextReference inContext, const RGBColor *fadeColor,  long fadeTicks ) 
  764. {
  765.     RGBColor inZeroIntensityColor;
  766.     OSStatus err = noErr;
  767.     long currTick;
  768.     UInt16 step = 800 / fadeTicks;
  769.     short x, percent = 0;
  770.  
  771. #ifdef kUseFades
  772.     if (fadeTicks == 0)
  773.         fadeTicks = 1;
  774.     if (fadeColor == NULL) 
  775.     {
  776.         inZeroIntensityColor.red = 0x0000;
  777.         inZeroIntensityColor.green = 0x0000;
  778.         inZeroIntensityColor.blue = 0x0000;
  779.     }
  780.     else 
  781.         inZeroIntensityColor = *fadeColor;
  782.     currTick = TickCount ();
  783.     for (x = 1; x <= fadeTicks; x++) 
  784.     {
  785.         percent =  step * x >> 3;
  786.         err = DSpContext_FadeGamma(inContext, percent, &inZeroIntensityColor);
  787.         if (err != noErr) 
  788.             break;
  789.         while (currTick >= TickCount ()) 
  790.             SystemTask ();
  791.         currTick = TickCount ();
  792.     }
  793.     if (err == noErr)
  794.         err = DSpContext_FadeGamma(inContext, 100, &inZeroIntensityColor);
  795. #endif // kUseFades
  796.     return err;
  797. }
  798.  
  799. //-----------------------------------------------------------------------------------------------------------------------
  800.  
  801. OSStatus DSpContext_CustomFadeGammaOut (DSpContextReference inContext, const RGBColor *fadeColor, long fadeTicks ) 
  802. {
  803.     RGBColor inZeroIntensityColor;
  804.     OSStatus err = noErr;
  805.     long currTick;
  806.     UInt16 step = 800 / fadeTicks;
  807.     short x, percent = 0;
  808.  
  809. #ifdef kUseFades
  810.     if (fadeTicks == 0)
  811.         fadeTicks = 1;                                // ensure we do not have zero fade time
  812.     if (fadeColor == NULL) 
  813.     {
  814.         inZeroIntensityColor.red = 0x0000;
  815.         inZeroIntensityColor.green = 0x0000;
  816.         inZeroIntensityColor.blue = 0x0000;
  817.     }
  818.     else 
  819.         inZeroIntensityColor = *fadeColor;
  820.     currTick = TickCount ();
  821.     for (x = fadeTicks - 1; x >= 0; x--) 
  822.     {
  823.         percent =  step * x >> 3;
  824.         err = DSpContext_FadeGamma(inContext, percent, &inZeroIntensityColor);
  825.         if (err != noErr) 
  826.             break;
  827.         while (currTick >= TickCount ()) 
  828.             SystemTask ();
  829.         currTick = TickCount ();
  830.     }
  831. #endif // kUseFades
  832.     return err;
  833. }